package com.jzz.exec;

import com.jzz.Options;
import com.jzz.algorithm.Algorithm;

import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.Base64;

public class CipherExecutor implements IExecutor {
    protected Options options;
    protected byte[] key;
    protected byte[] data;
    protected byte[] result;

    public CipherExecutor(Options options) {
        this.options = options;
        handleKey();
        handleInput();
        result = execute();
        handleOutput();
    }

    private void handleKey() {
        if (options.getKeyFile() != null) {
            try {
                InputStream is = new FileInputStream(options.getKeyFile());
                key = new byte[is.available()];
                is.read(key, 0, key.length);
                is.close();
            } catch (Exception e) {
                System.out.println("Error: Cannot open or read key file " + options.getKeyFile().getAbsolutePath());
            }
        } else {
            key = options.getKey();
        }

    }

    private void handleInput() {
        if (options.getInFile() != null) {
            try {
                InputStream is = new FileInputStream(options.getInFile());
                data = new byte[is.available()];
                is.read(data, 0, data.length);
                is.close();

                if (options.getInputB64()) {
                    data = Base64.getDecoder().decode(data);
                }
            } catch (Exception e) {
                System.out.println("Error: Cannot open or read file " + options.getInFile().getAbsolutePath());
            }
        } else {
            data = options.getData();

            if (options.getInputB64()) {
                data = Base64.getDecoder().decode(data);
            }
        }
    }

    private void handleOutput() {
        if (options.getOutFile() != null) {
            try {
                if (!options.getOutFile().exists()) {
                    if (!options.getOutFile().getParentFile().exists()) {
                        options.getOutFile().getParentFile().mkdirs();
                    }
                    options.getOutFile().createNewFile();
                }

                BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(options.getOutFile()));

                if (options.getOutputB64()) {
                    result = Base64.getEncoder().encode(result);
                }

                bos.write(result, 0, result.length);
                bos.flush();
                bos.close();
            } catch (Exception e) {
                System.out.println("Error: Cannot create or write file " + options.getOutFile().getAbsolutePath());
            }
        } else {
            if (options.getOutputB64()) {
                result = Base64.getEncoder().encode(result);
            }

            System.out.println(new String(result));
        }
    }

    @Override
    public byte[] execute() {
        Algorithm algorithm = options.getAlgorithm().setKey(key);
        if (algorithm == null) {
            return new byte[0];
        }
        if (options.getDecryption()) {
            return algorithm.decrypt(data);
        } else {
            return algorithm.encrypt(data);
        }
    }
}
